#pragma	once

#include "ZStreamable.h"
#include "ZStreamBuf.h"
#include "ZStreamVerifier.h"
#include "ZPoolObject.h"
#include "ZLockPolicy.h"
#include <boost/shared_ptr.hpp>

namespace	Z	{

//------------------------------------------------------------------------------------------------------------------------

class	Stream
	:	public Streamable,
		public PoolObject
{
private:
	Stream&	operator=(const Stream&);
public:
	Stream(const Stream& rhs)	:	mStreamBuf(rhs.mStreamBuf),	mRead(rhs.mRead),	mWritten(rhs.mWritten)	{
	}
	explicit	Stream(size_t kSize = autoSize)	:	mStreamBuf(new StreamBuf(kSize)),	mRead(0),	mWritten(0)	{
	}
	byte_t*	getBuffer()	const	{
		return mStreamBuf->getBuffer();
	}
	size_t	size()	const	{
		return mWritten;
	}
	virtual	void	write(const void* data, size_t kSize)	{
		WriteStreamVerifier::verify(*this, kSize);
		::memcpy(getWritableBuffer(), data, kSize);
		onWritten(kSize);
	}
	virtual	void	read(void* data, size_t kSize)	{
		peek(data, kSize);
		pop(kSize);
	}
	void	peek(void* data, size_t kSize)	const	{
		ReadStreamVerifier::verify(*this, kSize);
		::memcpy(data, getReadableBuffer(), kSize);
	}
	void	pop(size_t kSize)	{
		onRead(kSize);
	}
	byte_t*	getWritableBuffer()	const	{
		return mStreamBuf->getBuffer() + mWritten;
	}
	size_t	getWritableSize()	const	{
		return mStreamBuf->getAllocSize() - mWritten;
	}
	byte_t*	getReadableBuffer()	const	{
		return mStreamBuf->getBuffer() + mRead;
	}
	size_t	getReadableSize()	const	{
		return mWritten - mRead;
	}
	void	onRead(size_t kSize)	{
		assert(mRead + kSize <= mWritten);
		mRead	+= kSize;	
	}
	void	onWritten(size_t kSize)	{
		assert(mWritten + kSize <= mStreamBuf->getAllocSize());
		mWritten	+= kSize;
	}

public:
	static	const	size_t	autoSize	= 4096;
private:
	size_t	mRead;
	size_t	mWritten;
	typedef	boost::shared_ptr<StreamBuf>	StreamBufPtr;
	StreamBufPtr	mStreamBuf;

	friend	ReadStreamVerifier;
	friend	WriteStreamVerifier;
};

}